#include <linux/init.h>
#include <linux/module.h>
#include <linux/spi/spi.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/kdev_t.h>

dev_t dev_num; // 设备号
struct cdev mcp2515_cdev; // 字符设备结构体
struct class *mcp2515_class; // 设备类
struct device *mcp2515_device; // 设备
struct spi_device *spi_dev; // SPI设备指针

// MCP2515芯片复位函数
void mcp2515_reset(void){
    int ret;
    char write_buf[] = {0xc0}; // 复位指令0x11000000即0xc0
    ret = spi_write(spi_dev, write_buf, sizeof(write_buf)); // 发送复位命令
    if(ret < 0){
        printk("spi_write is error\n"); // 打印错误信息
    }
}

// MCP2515读寄存器函数
char mcp2515_read_reg(char reg) {
    char write_buf[] = {0x03, reg};  // SPI写缓冲区写入SPI读指令0x03
    char read_buf;                   // SPI读缓冲区
    int ret;

    ret = spi_write_then_read(spi_dev, write_buf, sizeof(write_buf), &read_buf, sizeof(read_buf));  // 调用SPI写读函数
    if (ret < 0) {
        printk("spi_write_then_read error\n");
        return ret;
    }

    return read_buf;
}


// 打开设备文件的回调函数
int mcp2515_open(struct inode *inode, struct file *file) {
    return 0; // 返回成功
}

// 读取设备文件的回调函数
ssize_t mcp2515_read(struct file *file, char __user *buf, size_t size, loff_t *offset) {
    return 0; // 返回成功
}

// 写入设备文件的回调函数
ssize_t mcp2515_write(struct file *file, const char __user *buf, size_t size, loff_t *offset) {
    return 0; // 返回成功
}

// 关闭设备文件的回调函数
int mcp2515_release(struct inode *inode, struct file *file) {
    return 0; // 返回成功
}

// 设备文件操作集合
struct file_operations mcp2515_fops = {
    .open = mcp2515_open,
    .read = mcp2515_read,
    .write = mcp2515_write,
    .release = mcp2515_release,
};

// MCP2515设备初始化函数
int mcp2515_probe(struct spi_device *spi) {
    int ret;
    int value;

    printk("This is mcp2515_probe\n");

    spi_dev = spi; // 保存SPI设备指针
    // 分配字符设备号
    ret = alloc_chrdev_region(&dev_num, 0, 1, "mcp2515");
    if (ret < 0) {
        printk("alloc_chrdev_region error\n");
    }

    // 初始化字符设备
    cdev_init(&mcp2515_cdev, &mcp2515_fops);
    mcp2515_cdev.owner = THIS_MODULE;

    // 添加字符设备
    ret = cdev_add(&mcp2515_cdev, dev_num, 1);
    if (ret < 0) {
        printk("cdev_add error\n");
        return -1;
    }

    // 创建设备类
    mcp2515_class = class_create(THIS_MODULE, "spi_to_can");
    if (IS_ERR(mcp2515_class)) {
        printk("mcp2515_class error\n");
        return PTR_ERR(mcp2515_class);
    }

    // 创建设备
    mcp2515_device = device_create(mcp2515_class, NULL, dev_num, NULL, "mcp2515");
    if (IS_ERR(mcp2515_device)) {
        printk("mcp2515_device error\n");
        return PTR_ERR(mcp2515_device);
    }

    mcp2515_reset();             // 复位MCP2515设备
    value = mcp2515_read_reg(0x0e);  // 读取寄存器值
    printk("value is %x\n", value);  // 打印读取的值
	
    return 0; // 返回成功
}

// MCP2515 SPI设备的移除函数
static int mcp2515_remove(struct spi_device *spi) {
    device_destroy(mcp2515_class, dev_num);
    class_destroy(mcp2515_class);
    cdev_del(&mcp2515_cdev);
    unregister_chrdev_region(dev_num, 1);
    return 0;
}

// MCP2515设备匹配表,用于设备树匹配
static const struct of_device_id mcp2515_of_match_table[] = {
    { .compatible = "my-mcp2515" },
    {}
};

// MCP2515设备ID匹配表,用于总线匹配
static const struct spi_device_id mcp2515_id_table[] = {
    { "mcp2515", 0 },
    {}
};

// MCP2515 SPI驱动结构体
static struct spi_driver spi_mcp2515 = {
    .probe = mcp2515_probe, // 探测函数
    .remove = mcp2515_remove, // 移除函数
    .driver = {
        .name = "mcp2515", // 驱动名称
        .owner = THIS_MODULE, // 所属模块
        .of_match_table = mcp2515_of_match_table, // 设备树匹配表
},
    .id_table = mcp2515_id_table, // 设备ID匹配表
};

// 驱动初始化函数
static int __init mcp2515_init(void)
{
    int ret;

    // 注册SPI驱动
    ret = spi_register_driver(&spi_mcp2515);
    if (ret < 0) {
        // 注册失败,打印错误信息
        printk("spi_register_driver error\n");
        return ret;
    }

    return ret;
}

// 驱动退出函数
static void __exit mcp2515_exit(void)
{
    // 注销SPI驱动
    spi_unregister_driver(&spi_mcp2515);
}

module_init(mcp2515_init);
module_exit(mcp2515_exit);

MODULE_LICENSE("GPL");
